/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package io.iec.edp.caf.caching.api;

import io.iec.edp.caf.caching.stats.CacheStats;
import io.iec.edp.caf.caching.support.CallableWrapper;

import java.util.*;

/**
 * 缓存接口
 */
public interface Cache {

    /**
     * 返回缓存名称
     *
     * @return String
     */
    String getName();

    /**
     * 返回真实Cache对象
     *
     * @return Object
     */
    Object getNativeCache();

    /**
     * 根据Key返回key对应的值，如果没有就返回NULL
     *
     * @param key key
     * @return 缓存key对应的值
     */
    Object get(Object key);

    /**
     * 根据KEY返回缓存中对应的值，并将其返回类型转换成对应类型，如果对应key不存在返回NULL
     *
     * @param key  缓存key
     * @param type 返回值类型
     * @param <T>  Object
     * @return 缓存key对应的值
     */
    <T> T get(Object key, Class<T> type);

    /**
     * 根据KEY返回缓存中对应的值，并将其返回类型转换成对应类型，如果对应key不存在则调用valueLoader加载数据
     *
     * @param key         缓存key
     * @param valueLoader 加载缓存的回调方法
     * @param <T>         Object
     * @return 缓存key对应的值
     */
    <T> T get(Object key, CallableWrapper<T> valueLoader);

    /**
     * 将对应key-value放到缓存，如果key原来有值就直接覆盖
     *
     * @param key   缓存key
     * @param value 缓存的值
     */
    void put(Object key, Object value);

    /**
     * 如果缓存key没有对应的值就将值put到缓存，如果有就直接返回原有的值
     * <p>就相当于:
     * <pre><code>
     * Object existingValue = cache.get(key);
     * if (existingValue == null) {
     *     cache.put(key, value);
     *     return null;
     * } else {
     *     return existingValue;
     * }
     * </code></pre>
     * except that the action is performed atomically. While all out-of-the-box
     * {@link CacheManager} implementations are able to perform the put atomically,
     * the operation may also be implemented in two steps, e.g. with a check for
     * presence and a subsequent put, in a non-atomic way. Check the documentation
     * of the native cache implementation that you are using for more details.
     *
     * @param key   缓存key
     * @param value 缓存key对应的值
     * @return 因为值本身可能为NULL，或者缓存key本来就没有对应值的时候也为NULL，
     * 所以如果返回NULL就表示已经将key-value键值对放到了缓存中
     * @since 4.1
     */
    Object putIfAbsent(Object key, Object value);

    /**
     * 在缓存中删除对应的key
     *
     * @param key 缓存key
     */
    void evict(Object key);

    /**
     * 清楚缓存
     */
    void clear();

    /**
     * 获取统计信息
     *
     * @return {@link CacheStats}
     */
    CacheStats getCacheStats();

    /**
     * 缓存存储hash类型数据，指定hash结构名称和键值对
     *
     * @param key       hash名称
     * @param hashKey   hash中存储的键
     * @param hashValue hash中存储的值
     */
    void putAsHash(Object key, Object hashKey, Object hashValue);

    /**
     * 返回缓存存储hash的所有键
     *
     * @param key hash名称
     * @return keys
     */
    Set<Object> getHashKeys(Object key);

    /**
     * 返回缓存存储hash中指定hashKey的值，并将返回值转化为指定类型
     *
     * @param key     hash名称
     * @param hashKey hash中的键
     * @param type    指定泛型
     * @param <T>     返回值类型
     * @return hash中某键对应的值
     */
    <T> T getHashValue(Object key, Object hashKey, Class<T> type);

    /**
     * 返回缓存存储hash的所有值
     *
     * @param key hash名称
     * @return values
     */
    List<Object> getHashValues(Object key);

    /**
     * 删除缓存存储hash中的一个或多个键值对
     *
     * @param key     hash名称
     * @param hashKey hash的键，一个或多个
     */
    void deleteHashKey(Object key, Object... hashKey);

    /**
     * 批量存储键值对
     *
     * @param map 键值map
     */
    void multiPut(Map<Object, Object> map);

    /**
     * 批量获取键值
     *
     * @param keys 键列表
     * @return 键值对map
     */
    Map<Object, Object> multiGet(List<Object> keys);

    /**
     * 批量删除键值对
     *
     * @param keys 键列表
     */
    void multiDel(Collection<Object> keys);

}
